

#include <iostream>
#include <memory>
#include <string>

// 工厂模式—— 一种创建型设计模式
// 将创建对象的逻辑不暴露给上层
// 使创建和使用分离
// 如果对象的创建逻辑发生变化，不需要大篇更改代码

// 1，简单工厂模式
// 该模式是一个工厂 ，生产不同的实例
// 优点：简单粗暴，直观移动
// 缺点：所有东西的生产都放在一起，产品太多会 导致代码量庞大

// class Fruit
// {
//     public:
//     virtual void name()=0;
// };

// class Apple : public Fruit
// {
//     public:
//     void name()
//     {
//         std::cout<<"我是一个苹果"<<std::endl;
//     }
// };

// class Banana:public Fruit
// {
//     public:
//     void name()
//     {
//         std::cout<<"我是一个香蕉"<<std::endl;
//     }
// };

// //工厂类
// //实例化不同的类
// 每新增一个水果，就需要修改工厂方法，违背了开闭原则——支持扩展，关闭修改
// class Factory
// {
//     public:
//     static std::shared_ptr<Fruit> create(const std::string& name)
//     {
//         if(name=="苹果")
//         {
//             return std::make_shared<Apple>();
//         }
//         else
//         {
//             return std::make_shared<Banana>();
//         }
//     }
// };

// int main()
// {
//     std::shared_ptr<Fruit> ff=Factory::create("苹果");
//     ff->name();
//     ff=Factory::create("香蕉");
//     ff->name();
//     return 0;
// }

// 2，工厂方法模式
// 每新增一个水果，就新增一个工厂，每个产品的生产都对应一个工厂
// 将每类产品的生产交给特定的一个工厂来进行
// 优点：减轻了工厂类的负担，遵循开闭原则
// 缺点：可能需要创建大量工厂
//  //遵循开闭原则
//  class Fruit
//  {
//      public:
//      virtual void name()=0;
//  };

// class Apple:public  Fruit
// {
//     public:
//     void name()
//     {
//         std::cout<<"我是一个苹果"<<std::endl;
//     }
// };

// class Banana:public Fruit
// {
//     public:
//     void name()
//     {
//         std::cout<<"我是一个香蕉"<<std::endl;
//     }
// };

// //基类工厂
// class FruitFactory
// {
//     public:
//     virtual std::shared_ptr<Fruit> create()=0;
// };

// //生产苹果的工厂
// class AppleFactory:public FruitFactory
// {
//     public:
//     std::shared_ptr<Fruit> create()
//     {
//         return std::make_shared<Apple>();
//     }
// };

// //生产香蕉的工厂
// class BananaFactory:public FruitFactory
// {
//     public:
//     std::shared_ptr<Fruit> create()
//     {
//         return std::make_shared<Banana>();
//     }
// };

// int main()
// {
//     std::shared_ptr<FruitFactory> ff(new AppleFactory());
//     //得到苹果实例
//     std::shared_ptr<Fruit> fruit=ff->create();
//     fruit->name();

//     //得到香蕉实例
//     ff.reset(new BananaFactory());
//     fruit=ff->create();
//     fruit->name();
//     return 0;
// }



// 工厂方法中，每个工厂只生产一类产品，可能会导致系统中存在大量的工厂
// 可以将相关的产品，形成一个产品族，类似于第一种简单工厂模式
// 3，抽象工厂模式
//通过一个超级工厂(抽象工厂),生产不同的子工厂(子工厂就是简单工厂模式)
//再通过子工厂,生成对应的产品
// 产品1
class Fruit
{
public:
    virtual void name() = 0;
};

class Apple : public Fruit
{
public:
    void name()
    {
        std::cout << "我是一个苹果" << std::endl;
    }
};

class Banana : public Fruit
{
public:
    void name()
    {
        std::cout << "我是一个香蕉" << std::endl;
    }
};
// 产品2
class Animal
{
public:
    virtual void name() = 0;
};

class Dog : public Animal
{
public:
    void name()
    {
        std::cout << "我是一只土狗" << std::endl;
    }
};

class Lamp : public Animal
{
public:
    void name()
    {
        std::cout << "我是一只山羊" << std::endl;
    }
};

// 抽象工厂
class Factory
{
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;
    virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};

// 水果产品工厂
class FruitFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string &name)
    {
        if (name == "苹果")
        {
            return std::make_shared<Apple>();
        }
        else
        {
            return std::make_shared<Banana>();
        }
    }
    std::shared_ptr<Animal> getAnimal(const std::string &name)
    {
        return std::shared_ptr<Animal>();
    }
};

// 动物产品工厂
class AnimalFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string &name)
    {

        return std::shared_ptr<Fruit>();
    }
    std::shared_ptr<Animal> getAnimal(const std::string &name)
    {
        if (name == "小狗")
        {
            return std::make_shared<Dog>();
        }
        else
        {
            return std::make_shared<Lamp>();
        }
    }
};

//获取到对应的工厂
class FactoryProducer
{
    public:
    static std::shared_ptr<Factory> getFactory(const std::string& name)
    {
        if(name=="动物")
        {
            return std::make_shared<AnimalFactory>();
        }
        else
        {
            return std::make_shared<FruitFactory>();
        }
    }
};

int main()
{
    //获取水果工厂
    std::shared_ptr<Factory> ff=FactoryProducer::getFactory("水果");
    //获取对应的产品工厂
    std::shared_ptr<Fruit> fruit=ff->getFruit("苹果");
    fruit->name();
    fruit=ff->getFruit("香蕉");
    fruit->name();

    //获取动物工厂
    std::shared_ptr<Factory> ff2=FactoryProducer::getFactory("动物");
    //获取对应的产品工厂
    std::shared_ptr<Animal> animal=ff2->getAnimal("小狗");
    animal->name();
    animal=ff2->getAnimal("山羊 ");
    animal->name();

    return 0;
}


//总结
//简单工厂模式:
//使用一个工厂产生任意产品(同类)
//优点：简单粗暴，直观易懂
//缺点：
//1，所有产品生产放在一起，产品太多会导致代码量庞大
//2，开闭原则遵循的不是很好——开闭原则(开放拓展,关闭修改)

//工厂方法模式
//在简单工厂模式下，新增多个工厂，每个工厂只负责生产一种产品
//优点：将某类产品的生产交给某个工厂执行，遵循开闭原则
//缺点：产品种类太多，就需要创建大量的工厂类


//抽象工厂模式
//通过一个超级工厂(抽象工厂),生产不同的子工厂(子工厂就是简单工厂模式)
//再通过子工厂,生成对应的产品